<?php
/**
 * 平台端件导出服务
 * User: dxk
 * Date: 2020/08/05
 */
namespace App\Service\Core\Admin\File;

use App\Library\Service\Upload;
use App\Model\Core\Admin\AdminFileModel;
use App\Service\Core\CoreBaseService;
use App\Service\EasyRedis;
use App\Traits\SingleInstanceTrait;

class AdminFileService extends CoreBaseService
{
    use SingleInstanceTrait;

    private $FileModel;
    private $Redis;
    private $key = 'admin_export_file:';

    public function __construct()
    {
        $this->FileModel = AdminFileModel::getInstance();
        $this->Redis = EasyRedis::getRedis();
    }

    /**
     * 获取一条文件信息
     * @param $file_id
     * @return array
     */
    public function getOne($file_id): array
    {
        $file_id = (int)$file_id;
        $info = $this->FileModel->getOne($file_id);
        if (!empty($info)) {
            $info['request'] = json_decode($info['request'], true);
        }
        return $info;
    }

    /**
     * 生成文件存储路径并创建目录
     * @param $file_name
     * @param int $is_storage_path 是否存放storage目录
     * @return string
     * @throws \Exception
     */
    public function makeFilePath($file_name, $is_storage_path = 0)
    {
        $dir_info = (new Upload(0))->getAttachDir('export', $is_storage_path);
        return $dir_info['store_path'] . $file_name;
    }

    /**
     * 取消下载
     * @param $file_id
     * @return array
     */
    public function applyCancel($file_id)
    {
        $file_id = (int)$file_id;
        $file_info = self::getOne($file_id);
        if (empty($file_info)) {
            return alert_info(1, '数据不存在');
        }
        $data = ['is_cancel' => 1];
        if ($file_info['status'] == AdminFileModel::STATUS_WAIT && $file_info['is_cancel'] == 0) {
            $data['status'] = AdminFileModel::STATUS_CANCELD;
        }
        $res = $this->FileModel->updateOne($file_id, $data);
        if ($res) {
            $key = $this->key . 'cancel' . $file_id;
            $this->Redis->setex($key, 3600 * 48, 1);
            return alert_info(0, '请求取消成功');
        }
        return alert_info(1, '操作失败');
    }

    /**
     * 检测是否取消下载
     * @param $file_id
     * @return bool
     */
    public function checkIsCancel($file_id)
    {
        $file_id = (int)$file_id;
        $key = $this->key . 'cancel' . $file_id;
        $is_cancel = $this->Redis->get($key);
        if ($is_cancel) {
            return true;
        }
        return false;
    }

    /**
     * 设置下载进度
     * @param int $file_id 文件ID
     * @param $progress
     * @return bool
     */
    public function setProgress($file_id, $progress): bool
    {
        $file_id = (int)$file_id;
        $progress = trim($progress);
        $key = $this->key . $file_id;
        $this->Redis->setex($key, 3600 * 48, $progress);
        return true;

    }

    /**
     * 获取进度
     * @param $file_id
     * @return float
     */
    public function getProcess($file_id)
    {
        $key = $this->key . $file_id;
        $process = $this->Redis->get($key);
        $file_info = self::getOne($file_id);
        if (empty($process)) {
            return AdminFileModel::$status[$file_info['status']];
        } else {
            return AdminFileModel::$status[$file_info['status']] . '(' . $process . ')';
        }
    }

    /**
     * 开始任务
     * @param $file_id
     * @return array
     */
    public function startJob($file_id)
    {
        $file_info = self::getOne($file_id);
        if (empty($file_info)) {
            return alert_info(1, '数据不存在');
        }
        if ($file_info['status'] != AdminFileModel::STATUS_WAIT) {
            return alert_info(1, '请求状态错误');
        }
        if ($file_info['is_cancel'] == 1) {
            return alert_info(1, '已取消下载');
        }
        $data = [
            'start_at' => date('Y-m-d H:i:s'),
            'status' => AdminFileModel::STATUS_PROCESSING
        ];
        $res = $this->FileModel->updateOne($file_id, $data);
        if ($res) {
            return alert_info(0, 'OK');
        }
        return alert_info(1, '操作失败');
    }

    /**
     * 结束任务
     * @param $file_id
     * @param $status
     * @param string $result
     * @param string $result_file_path
     * @return array
     */
    public function endJob($file_id, $status, $result = '', $result_file_path = '')
    {
        $file_id = (int)$file_id;
        $status = (int)$status;
        $result = trim($result);
        $result_file_path = trim($result_file_path);
        $file_info = self::getOne($file_id);
        if (empty($file_info)) {
            return alert_info(1, '数据不存在');
        }
        $data = [
            'status' => $status,
            'result' => $result,
            'file_path' => $result_file_path,
            'end_at' => date('Y-m-d H:i:s')
        ];
        $res = AdminFileModel::getInstance()->updateOne($file_id, $data);
        $data['file_id'] = $file_id;
        if ($res) {
            self::setProgress($file_id, '已结束');
            return alert_info(0, 'OK', $data);
        } else {
            return alert_info(1, '数据库操作失败', $data);
        }
    }

    /**
     * 下载
     * @param $file_id
     * @return array
     */
    public function download($file_id)
    {
        $file_info = self::getOne($file_id);
        if (empty($file_info)) {
            return alert_info(1, '数据不存在');
        }
        if (empty($file_info['file_path'])) {
            return alert_info(1, '文件未打包成功');
        }
        $data = [
            'last_download_at' => date('Y-m-d H:i:s'),
            'download_times' => $file_info['download_times'] + 1
        ];
        $res = $this->FileModel->updateOne($file_id, $data);
        if ($res) {
            return alert_info(0, 'OK', $file_info);
        }
        return alert_info(1, '操作失败');
    }
}
